package blackstar.performance;

import java.text.NumberFormat;
import java.util.logging.Logger;

import blackstar.performance.logger.MessageBuilder;
import blackstar.performance.logger.RollingFileLogger;

public class WebPerformance implements WebPerformanceMBean
{
	private final static Logger LOGGER = Logger.getLogger(WebPerformance.class
			.getSimpleName());

	public final static String BEAN_NAME = "name=WebPerformance";

	private static RollingFileLogger rollingFileLogger = null;;

	private static boolean appendTime = false;// 是否输出时间信息

	private static long totalInvokes = 0L;
	private static long totalPerfTimeNano = 0L;
	private static long totalTimeNano = 0L;
	private final static boolean stat;
	static
	{
		String isStat = System.getProperty("statperm");
		stat = !("false".equalsIgnoreCase(isStat));
		LOGGER.info("state:" + stat + ";appendTime:" + appendTime);
	}
	private static final Object LOCK = new Object();

	public static boolean isStat()
	{
		return WebPerformance.stat;
	}

	public static long getTotalInvokes()
	{
		return WebPerformance.totalInvokes;
	}

	public static long getTotalTimeNano()
	{
		return WebPerformance.totalTimeNano;
	}

	public static long getTotalPerfTimeNano()
	{
		return WebPerformance.totalPerfTimeNano;
	}

	public static synchronized void init(RollingFileLogger rollingFileLogger,
			boolean appendTime)
	{
		if (WebPerformance.rollingFileLogger != null)
		{
			WebPerformance.rollingFileLogger = rollingFileLogger;
			WebPerformance.appendTime = appendTime;
			if (WebPerformance.isStat())
			{
				MBeanRegister.registMBean(BEAN_NAME, new WebPerformance());
			}
		}
	}

	public static void handle(String uri, String methodName, int status,
			int contentLength, int processTimeNano)
	{
		if (WebPerformance.stat)
		{
			long time = System.nanoTime();
			log(uri, methodName, status, contentLength, processTimeNano);
			time = System.nanoTime() - time;
			synchronized (LOCK)
			{
				WebPerformance.totalPerfTimeNano += time;
				WebPerformance.totalTimeNano += processTimeNano;
				WebPerformance.totalInvokes++;
			}
		} else
		{
			log(uri, methodName, status, contentLength, processTimeNano);
		}
	}

	public static void log(String uri, String methodName, int status,
			int contentLength, int processTimeNano)
	{
		MessageBuilder builder = new MessageBuilder();
		builder.append(uri);
		builder.appendSplit();
		builder.append(methodName);
		builder.appendSplit();
		builder.append(status);
		builder.appendSplit();
		builder.append(contentLength);
		builder.appendSplit();
		builder.append(processTimeNano);
		if (WebPerformance.appendTime)
		{
			builder.appendSplit();
			builder.appendTimestamp();
		}
		builder.appendLineSep();
		rollingFileLogger.log(builder.getMessage());
	}

	public long getInvokes()
	{
		return WebPerformance.totalInvokes;
	}

	public long getPerfTimeNano()
	{
		return WebPerformance.totalPerfTimeNano;
	}

	public long getTimeNano()
	{
		return WebPerformance.totalTimeNano;
	}

	private final static long MILLISECONDS = 1000000L;

	public String getInvokeMessage()
	{
		long invokes = WebPerformance.totalInvokes;
		long timePerfNano = WebPerformance.totalPerfTimeNano;
		long timeNano = WebPerformance.totalTimeNano;

		NumberFormat timeFormat = NumberFormat.getNumberInstance();
		timeFormat.setMaximumFractionDigits(3);

		StringBuilder message = new StringBuilder();
		message.append("Invokes=");
		message.append(invokes);
		message.append(",PerfTimes=");
		message.append(timeFormat
				.format(((double) timePerfNano) / MILLISECONDS));
		message.append("ms");
		message.append(",AvarageTimes=");
		message.append(timeFormat.format(((double) timePerfNano) / invokes));
		message.append("ns");
		message.append(",Times=");
		message.append(timeFormat.format(((double) timeNano) / MILLISECONDS));
		message.append("ms");
		if (timeNano > 0)
		{
			message.append(",PerfPercent=");
			message.append(timeFormat.format((((double) timePerfNano) * 100)
					/ (double) (timePerfNano + timeNano)));
			message.append("%");
		}

		return message.toString();
	}

}
